package com.ruoyi.common.core.domain;

import cn.hutool.core.util.StrUtil;
import lombok.Data;

import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author wangxianl
 * createTime: 2020-8-24.
 * description: 指标查询实体
 */
@Data
public class ItemConditionVo implements Serializable {

    /**
     * 操作符
     */
    public static class Operation {
        /**
         * 开头是
         */
        public static final String BEGIN_WITH = "beginWith";
        /**
         * 结尾是
         */
        public static final String END_WITH = "endWith";

        /**
         * 包含
         */
        public static final String LIKE = "like";

        /**
         * 等于
         */
        public static final String EQUALS = "=";

        /**
         * 不等于
         */
        public static final String NOT_EQUALS = "!=";

        /**
         * 大于
         */
        public static final String GREATER_THAN = ">";

        /**
         * 大于等于
         */
        public static final String GREATER_EQUALS = ">=";

        /**
         * 小于
         */
        public static final String LESS_THAN = "<";

        /**
         * 小于等于
         */
        public static final String LESS_EQUALS = "<=";

        /**
         * 非空
         */
        public static final String IS_NOT_NULL = "isNotNull";

        /**
         * 非空
         */
        public static final String IS_NULL = "isNull";

        /**
         * 字符非空
         */
        public static final String IS_NOT_BLANK = "isNotBlank";

        /**
         * 字符为空
         */
        public static final String IS_BLANK = "isBlank";

        /**
         * 包含
         */
        public static final String IN = "in";
    }

    /**
     * 指标类型
     */
    public static class ItemType {
        /**
         * 字符型指标
         */
        public static final int CHAR = 1;

        /**
         * 分组型指标
         */
        public static final int GROUP = 2;

        /**
         * 数字型指标
         */
        public static final int NUMBER = 3;
    }

    /**
     * 指标排序规则
     */
    private static class ItemSortRule {

        /**
         * 按类型自动匹配
         */
        public static final int AUTO = 0;

        /**
         * 按字符排序
         */
        public static final int CHAR = 1;

        /**
         * 按数字排序
         */
        public static final int NUMBER = 2;
    }

    /**
     * 字段
     */
    private String field;

    /**
     * 操作符
     */
    private String operation;

    /**
     * 数值
     */
    private String value;

    /**
     * 逻辑 与或关系
     */
    private String logic = "and";

    /**
     * 缩进
     */
    private boolean tab = false;

    /**
     * 类型
     */
    private Integer type = ItemType.CHAR;

    /**
     * 排序规则
     */
    private Integer sortRule = ItemSortRule.AUTO;

    @Override
    public String toString() {
        //字段或操作符为空时直接返回空
        if (StrUtil.isBlank(this.field) || StrUtil.isBlank(this.operation)) {
            return "";
        }
        String toNumberField = this.getField();
        //是否数字型
        boolean isNumber = (this.sortRule.equals(ItemSortRule.AUTO) && this.type.equals(ItemType.NUMBER)) || this.sortRule.equals(ItemSortRule.NUMBER);
        //是否字符型
        boolean isChar = (this.sortRule.equals(ItemSortRule.AUTO) && (this.type.equals(ItemType.CHAR) || this.type.equals(ItemType.GROUP))) || this.sortRule.equals(ItemSortRule.CHAR);
        if (isNumber) {
            toNumberField = this.getField() + "+0";
        }
        //根据操作符设置
        switch (this.operation) {
            //开头是
            case Operation.BEGIN_WITH:
                return this.field + " like '" + this.value + "%'";
            //结尾是
            case Operation.END_WITH:
                return this.field + " like '%" + this.value + "'";
            //包含
            case Operation.LIKE:
                return this.field + " like '%" + this.value + "%'";
            //包含
            case Operation.IN:
                return this.field + " in (" + this.value + ")";
            //    为空
            case Operation.IS_NULL:
                return this.field + " is null";
            //    非空
            case Operation.IS_NOT_NULL:
                return this.field + " is not null";
            //    字符为空
            case Operation.IS_BLANK:
                return this.field + " is null or " + this.field + " = ''";
            //    字符非空
            case Operation.IS_NOT_BLANK:
                return this.field + " is not null and " + this.field + " != ''";
            default:
                //默认直接连接起来
                return toNumberField + " " + this.operation + (isChar ? ("'" + this.value + "'") : this.value);
        }
    }

    /**
     * 将列表转换为条件字符串
     *
     * @param itemCondList 指标条件列表
     * @return 查询条件公式字符串
     */
    public static String fmtItemCondList(List<ItemConditionVo> itemCondList) {
        //非空的条件列表
        List<ItemConditionVo> notNullCondList = itemCondList.stream().filter(cond -> cond.toString().length() > 0).collect(Collectors.toList());
        StringBuilder sb = new StringBuilder();
        //设置缩进相关
        int size = notNullCondList.size();
        for (int i = 0; i < size; i++) {
            ItemConditionVo cond = notNullCondList.get(i);
            boolean isFirst = false, isLast = false;
            if (cond.isTab()) {
                //判断是否为括号开始
                if (i == 0) {
                    isFirst = true;
                } else {
                    ItemConditionVo preCond = notNullCondList.get(i - 1);
                    isFirst = !preCond.isTab();
                }
                //判断是否为括号结束
                if (i == size - 1) {
                    isLast = true;
                } else {
                    ItemConditionVo nextCond = notNullCondList.get(i + 1);
                    isLast = !nextCond.isTab();
                }
            }
            //设置条件
            if (isFirst) {
                sb.append(" (");
            }
            sb.append(" (").append(cond.toString()).append(") ");

            if (isLast) {
                sb.append(") ");
            }
            //最后一个不添加逻辑关系
            if (i < size - 1) {
                sb.append(cond.getLogic());
            }
        }
        return sb.toString();
    }
}
